package com.huitong.common.dubbo.filter;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import com.huitong.common.dubbo.enums.LogLevel;
import com.huitong.common.dubbo.properties.DubboCustomProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.service.GenericService;

/**
 * Dubbo日志过滤器
 *
 * @author fromdrowning
 * @date 2024/3/22 22:58
 */
@Slf4j
@Activate(group = {CommonConstants.PROVIDER, CommonConstants.CONSUMER}, order = Integer.MAX_VALUE)
public class DubboRequestFilter implements Filter {

    /**
     * {@link DubboCustomProperties}实例
     */
    private static final DubboCustomProperties DUBBO_CUSTOM_PROPERTIES = SpringUtil.getBean(DubboCustomProperties.class);

    /**
     * 打印日志信息
     *
     * @param invoker    执行原接口
     * @param invocation 原接口的方法参数
     * @return 执行原接口方法返回的结果
     * @throws RpcException 执行原接口方法发生异常抛出此异常
     */
    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        // 未开启日志直接返回
        if (!DUBBO_CUSTOM_PROPERTIES.isRequestLog()) {
            return invoker.invoke(invocation);
        }

        String client = RpcContext.getServiceContext().isConsumerSide() ? CommonConstants.CONSUMER : CommonConstants.PROVIDER;
        String baseLog = "Client[" + client + "] " +
            "接口名[" + invocation.getInvoker().getInterface().getSimpleName() + "] " +
            "方法名[" + invocation.getMethodName() + "]";

        if (DUBBO_CUSTOM_PROPERTIES.getLogLevel() == LogLevel.INFO) {
            log.info("[Dubbo] 服务调用:{}", baseLog);
        } else {
            log.info("[Dubbo] 服务调用:{} 参数:{}", baseLog, invocation.getArguments());
        }

        // 计算耗时并执行接口逻辑
        long startTime = System.currentTimeMillis();
        Result result = invoker.invoke(invocation);
        long elapsed = System.currentTimeMillis() - startTime;

        // 发生异常 打印异常日志
        if (result.hasException() && invoker.getInterface().equals(GenericService.class)) {
            log.error("[Dubbo] 服务异常:{}", baseLog, result.getException());
        } else {
            if (DUBBO_CUSTOM_PROPERTIES.getLogLevel() == LogLevel.INFO) {
                log.info("[Dubbo] 服务响应:{} 响应时间:{}ms", baseLog, elapsed);
            } else if (DUBBO_CUSTOM_PROPERTIES.getLogLevel() == LogLevel.FULL) {
                log.info("[Dubbo] 服务响应:{} 响应时间:{}ms 响应内容:{}", baseLog, elapsed, JSONUtil.toJsonStr(result.getValue()));
            }
        }

        return result;
    }
}
